package third;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 代理生成Util
 *
 * @author zengjian
 * @create 2018-06-06 14:50
 * @since 1.0.0
 */
public final class ProxyUtil {

    public static final Interceptor EMPTY_INTERCEPTOR = new Interceptor() {

        @Override
        public Object preHandle() {
            return null;
        }

        @Override
        public Object handleResult(Object result) {
            return null;
        }

        @Override
        public Object postHandle() {
            return null;
        }
    };

    private ProxyUtil() {
    }

    /**
     * jdk方式生成代理类
     *
     * @param src 被代理实例
     * @return Object 代理对象
     */
    public static Object createProxyByJDK(final Object src) {
        if (src == null) {
            return src;
        }
        return doCreateProxyByJDK(src, EMPTY_INTERCEPTOR);
    }

    public static Object createProxyByCGLIB(final Class<?> clazz) {
        if (clazz == null) {
            return clazz;
        }
        return doCreateProxyByCGLIB(clazz, EMPTY_INTERCEPTOR);
    }

    private static Object doCreateProxyByJDK(final Object src, final Interceptor invoker) {
        Object target = Proxy.newProxyInstance(src.getClass().getClassLoader(), src.getClass().getInterfaces(), new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                invoker.preHandle();
                Object result = method.invoke(src, args);
                invoker.handleResult(result);
                invoker.postHandle();
                return result;
            }
        });
        return target;
    }

    public static Object doCreateProxyByCGLIB(final Class<?> clazz, final Interceptor invoker) {
        final Interceptor interceptor = invoker != null ? invoker : EMPTY_INTERCEPTOR;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                interceptor.preHandle();
                Object result = proxy.invokeSuper(obj, args);
                interceptor.handleResult(result);
                interceptor.postHandle();
                return result;
            }
        });
        return enhancer.create();
    }

    public static Object doCreateProxyByCGLIB(final Class<?> clazz, MethodInterceptor interceptor) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(interceptor);
        return enhancer.create();
    }

    public interface Interceptor {

        /**
         * 方法执行前处理
         *
         * @return
         */
        Object preHandle();

        /**
         * 方法返回结果处理
         *
         * @param result
         * @return
         */
        Object handleResult(Object result);

        /**
         * 返回结果后处理
         *
         * @return
         */
        Object postHandle();
    }
}
